package model;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;

public class Employee extends Model
{
	public static final int			EMPLOYEE_ALL								= 0;
	public static final int			EMPLOYEE_CATEGORY_SENIOR_STEWARDS			= 1;
	public static final int			EMPLOYEE_CATEGORY_SENIOR_ASSIST_STEWARDS	= 2;
	public static final int			EMPLOYEE_CATEGORY_STEWARDS					= 3;

	public static final boolean		EMPLOYEE_GENDER_MALE						= true;
	public static final boolean		EMPLOYEE_GENDER_FEMALE						= false;

	public static final boolean		SAATSAN										= true;
	public static final boolean		SAATAAGUI									= false;

	private String					name;																			//
	private int						age;																			//
	private boolean					gender;																		//
	private Date					passportExpiredDate;															//
	private String					passportNumber;																//
	private float					flyTimeTotal;																	//
	// private float flyTimeMonth;
	// private float flyTimeWeek;
	private int						rank;																			//
	private int						category;																		//
	private Date					arriveDate;
	private int						totalWorkingYear;
	// private float willFlyTimeOnThisMonth;
	private boolean					teacher;
	private float					berlin;
	private Set<FlyEmployee>		flyEmployees								= new HashSet<FlyEmployee>();
	private Set<EmployeeLanguage>	employeeLanguages							= new HashSet<EmployeeLanguage>();
	private Set<Stay>				stays										= new HashSet<Stay>();

	public Employee()
	{

	}

	public static String getCategoryName(int categoryCode)
	{
		switch (categoryCode)
		{
			case EMPLOYEE_CATEGORY_SENIOR_STEWARDS:
				return "Агаарын хөлгийн ахлах үйлчилэгч";
			case EMPLOYEE_CATEGORY_STEWARDS:
				return "Агаарын хөлгийн үйлчилэгч";
			case EMPLOYEE_CATEGORY_SENIOR_ASSIST_STEWARDS:
				return "Ахлах үйлчилэгчийн туслах";
			default:
				return "";
		}
	}

	public String getCategoryName()
	{
//		switch (this.getCategory())
//		{
//			case EMPLOYEE_CATEGORY_SENIOR_STEWARDS:
//				return "Агаарын хөлгийн ахлах үйлчилэгч";
//			case EMPLOYEE_CATEGORY_STEWARDS:
//				return "Агаарын хөлгийн үйлчилэгч";
//			case EMPLOYEE_CATEGORY_SENIOR_ASSIST_STEWARDS:
//				return "Ахлах үйлчилэгчийн туслах";
//			default:
//				return "";
//		}
		switch (this.getCategory())
		{
			case EMPLOYEE_CATEGORY_SENIOR_STEWARDS:
				return "AXAY";
			case EMPLOYEE_CATEGORY_STEWARDS:
				return "AXY";
			case EMPLOYEE_CATEGORY_SENIOR_ASSIST_STEWARDS:
				return "AXAY assist";
			default:
				return "";
		}
	}

	public String getGenderString()
	{
		if ( this.isGender() )
			return "Эрэгтэй";
		else
			return "Эмэгтэй";
	}

	public static int getCategoryCount()
	{
		return 2;
	}

	public static Employee getEmployeeByPk(Session session, long pk)
	{
		Criteria criteria = session.createCriteria(Employee.class);
		Criterion criterion = Restrictions.idEq(pk);
		criteria.add(criterion);
		return (Employee) criteria.uniqueResult();
	}

	public static ArrayList<Employee> getAvailableEmployee(Session session, ArrayList<Employee> allEmployees, Fly willFly, boolean checkCategory, int category, boolean checkGender, boolean gender, int limit)
	{
		ArrayList<Employee> currentEmployees = getEmployeesByFly(session, willFly);
		ArrayList<Long> currentEmployeesId = new ArrayList<Long>();
		for (Employee employee : currentEmployees)
		{
			currentEmployeesId.add(employee.getId());
		}

		ArrayList<Employee> resultArray = new ArrayList<Employee>();
		int count = 0;
		for (Employee employee : allEmployees)
		{
			boolean isEmployeeRelaxed = isEmployeeRelaxedForThisFly(session, willFly, employee);
			if ( (checkCategory ? (employee.getCategory() == category) : true) && (checkGender ? (employee.isGender() == gender) : true) && isEmployeeRelaxed &&
			// !employee.isSaatsan() &&
			!currentEmployeesId.contains(employee.getId()) )
			{
				resultArray.add(employee);
				if ( ++count == limit )
					break;
			}
		}
		return resultArray;
	}

	@SuppressWarnings("unchecked")
	public static ArrayList<Employee> getAllEmployeeByFlyTimeASC(Session session, boolean berlin, boolean category)
	{
		Criteria criteria = session.createCriteria(Employee.class);
		if ( category )
			criteria.addOrder(Order.asc("category"));
		// criteria.addOrder(Order.asc("willFlyTimeOnThisMonth"));
		if ( berlin )
			criteria.addOrder(Order.asc("berlin"));
		// criteria.addOrder(Order.asc("flyTimeWeek"));
		// criteria.addOrder(Order.asc("flyTimeMonth"));
		criteria.addOrder(Order.asc("flyTimeTotal"));
		return (ArrayList<Employee>) criteria.list();
	}

	@SuppressWarnings("unchecked")
	public static ArrayList<Employee> getAllEmployeeByFlyTimeASCAndNameASC(Session session)
	{
		Criteria criteria = session.createCriteria(Employee.class);
		criteria.addOrder(Order.asc("category"));
		criteria.addOrder(Order.asc("name"));
		return (ArrayList<Employee>) criteria.list();
	}

	@SuppressWarnings("unchecked")
	public static ArrayList<Employee> getAllEmployeeByNameASC(Session session, int category)
	{
		Criteria criteria = session.createCriteria(Employee.class);
		Criterion criterion = Restrictions.eq("category", category);
		criteria.add(criterion);
		criteria.addOrder(Order.asc("name"));
		return (ArrayList<Employee>) criteria.list();
	}

	public static boolean isEmployeeRelaxedForThisFly(Session session, Fly fly, Employee employee)
	{
		Date employeeArriveDate = employee.getArriveDate();
		if ( employeeArriveDate == null )
		{
			return true;
		}
		Date willFlyDate = fly.getDate1();

		Fly lastFlyOfEmployee = Fly.getLastFly(session, employee);
		if ( lastFlyOfEmployee == null )
			return true;
		float relaxHourOnDst = 0;
		if ( lastFlyOfEmployee.isVia() )
		{
			if ( lastFlyOfEmployee.getDate4() == null || lastFlyOfEmployee.getDate5() == null )
				return true;
			relaxHourOnDst = getDateDifference(lastFlyOfEmployee.getDate4(), lastFlyOfEmployee.getDate5());
		}
		else
		{
			if ( lastFlyOfEmployee.getDate2() == null || lastFlyOfEmployee.getDate3() == null )
				return true;
			relaxHourOnDst = getDateDifference(lastFlyOfEmployee.getDate2(), lastFlyOfEmployee.getDate3());
		}
		float hourDiff = getDateDifference(employeeArriveDate, willFlyDate);
		if ( relaxHourOnDst >= 60 )
		{
			if ( hourDiff >= 36 )
				return true;
			else
				return false;
		}
		else
		{
			if ( hourDiff >= 8 )
				return true;
			else
				return false;
		}
	}

	public static float getDateDifference(Date date1, Date date2)
	{
		float diff = date1.getTime() - date2.getTime();
		float intDiff = (diff / (1000 * 60 * 60));
		if ( intDiff < 0 )
			return intDiff * -1;
		return intDiff;
	}

	@SuppressWarnings("unchecked")
	public static ArrayList<Employee> getEmployeesByFly(Session session, Fly fly)
	{
		Criteria employeeCriteria = session.createCriteria(Employee.class);
		Criteria flyEmployeeCriteria = employeeCriteria.createCriteria("flyEmployees");
		Criteria flyCriteria = flyEmployeeCriteria.createCriteria("fly");
		Criterion criterion = Restrictions.idEq(fly.getId());
		flyCriteria.add(criterion);
		return (ArrayList<Employee>) employeeCriteria.list();
	}

	@SuppressWarnings("unchecked")
	public static ArrayList<Employee> getEmployeesByFlyForBerlinLongTimeDelay(Session session, Fly fly)
	{
		Criteria employeeCriteria = session.createCriteria(Employee.class);

		Criteria flyEmployeeCriteria = employeeCriteria.createCriteria("flyEmployees");
		Criterion flyEmployeeCriterion = Restrictions.eq("specified", false);
		flyEmployeeCriteria.add(flyEmployeeCriterion);

		Criteria flyCriteria = flyEmployeeCriteria.createCriteria("fly");
		Criterion criterion = Restrictions.idEq(fly.getId());
		flyCriteria.add(criterion);

		employeeCriteria.addOrder(Order.asc("berlin"));
		return (ArrayList<Employee>) employeeCriteria.list();

	}

	public float getWillFlyTimeOnThisMonth(boolean deep, Session session)
	{
		float totalTime = 0.0f;
		Set<FlyEmployee> flyEmployees = null;
		if ( deep )
		{
			// Employee employee = (Employee) session
			// .createCriteria(Employee.class)
			// .add(Restrictions.idEq(this.getId())).uniqueResult();
			Employee employee = (Employee) session.load(Employee.class, this.getId());
			flyEmployees = employee.getFlyEmployees();
		}
		else
		{
			flyEmployees = this.getFlyEmployees();
		}
		for (FlyEmployee flyEmployee : flyEmployees)
		{
			Fly fly = flyEmployee.getFly();
			// if ( fly.isVia() )
			// {
			// float diff1 = Employee.getDateDifference(fly.getDate1(),
			// fly.getDate4());
			// float diff2 = Employee.getDateDifference(fly.getDate5(),
			// fly.getDate8());
			// totalTime += (diff1 + diff2);
			// }
			// else
			// {
			// totalTime += Employee.getDateDifference(fly.getDate1(),
			// fly.getDate4());
			// }
			totalTime += flyHour(fly);
		}
		return totalTime;
	}

	public float flyHour(Fly fly)
	{
		int flyId = (int) fly.getDstPosition().getId();
		switch (flyId)
		{
			case 1:
				return 0;
			case 2:
				return 4.5f;
			case 3:
				return 8.83f;
			case 4:
				return 6.5f;
			case 5:
				return 10.25f;
			case 6:
				return 10.25f;
			case 7:
				return 8.25f;
			case 8:
				return 17.5f;
			default:
				return 0;
		}
	}

	public ArrayList<Long> getCurrentLanguagesId()
	{
		ArrayList<Long> employeeCurrentLanguagesId = new ArrayList<Long>();
		for (EmployeeLanguage employeeLanguage : this.getEmployeeLanguages())
			employeeCurrentLanguagesId.add(employeeLanguage.getLanguage().getId());
		return employeeCurrentLanguagesId;
	}

	@SuppressWarnings("unchecked")
	public static ArrayList<Long> getCurrentLanguagesId(Session session, Employee employee)
	{
		ArrayList<Long> employeeCurrentLanguagesId = new ArrayList<Long>();

		Criteria criteria = session.createCriteria(EmployeeLanguage.class);
		Criterion criterion = Restrictions.eq("employee", employee);
		criteria.add(criterion);
		for (EmployeeLanguage employeeLanguage : (ArrayList<EmployeeLanguage>) criteria.list())
			employeeCurrentLanguagesId.add(employeeLanguage.getLanguage().getId());
		return employeeCurrentLanguagesId;
	}

	public String getName(boolean withSymbol)
	{
		if ( withSymbol )
		{
			if ( this.gender == Employee.EMPLOYEE_GENDER_MALE )
			{
				return "@" + name;
			}
		}
		return name;
	}

	public String getName()
	{
		return name;
	}

	public void setName(String name)
	{
		this.name = name;
	}

	public int getAge()
	{
		return age;
	}

	public void setAge(int age)
	{
		this.age = age;
	}

	public boolean isGender()
	{
		return gender;
	}

	public void setGender(boolean gender)
	{
		this.gender = gender;
	}

	public Date getPassportExpiredDate()
	{
		return passportExpiredDate;
	}

	public void setPassportExpiredDate(Date passportExpiredDate)
	{
		this.passportExpiredDate = passportExpiredDate;
	}

	public float getFlyTimeTotal()
	{
		return flyTimeTotal;
	}

	public void setFlyTimeTotal(float flyTimeTotal)
	{
		this.flyTimeTotal = flyTimeTotal;
	}

	// public float getFlyTimeMonth() {
	// return flyTimeMonth;
	// }
	// public void setFlyTimeMonth(float flyTimeMonth) {
	// this.flyTimeMonth = flyTimeMonth;
	// }
	public Set<FlyEmployee> getFlyEmployees()
	{
		return flyEmployees;
	}

	public void setFlyEmployees(Set<FlyEmployee> flyEmployees)
	{
		this.flyEmployees = flyEmployees;
	}

	public int getRank()
	{
		return rank;
	}

	public void setRank(int rank)
	{
		this.rank = rank;
	}

	public int getCategory()
	{
		return category;
	}

	public void setCategory(int category)
	{
		this.category = category;
	}

	public float getBerlin()
	{
		return berlin;
	}

	public void setBerlin(float berlin)
	{
		this.berlin = berlin;
	}

	// public float getBerlin7() {
	// return berlin7;
	// }
	// public void setBerlin7(float berlin7) {
	// this.berlin7 = berlin7;
	// }
	// public float getBeijing() {
	// return beijing;
	// }
	// public void setBeijing(float beijing) {
	// this.beijing = beijing;
	// }
	// public float getTokyo() {
	// return tokyo;
	// }
	// public void setTokyo(float tokyo) {
	// this.tokyo = tokyo;
	// }
	// public float getMoscow() {
	// return moscow;
	// }
	// public void setMoscow(float moscow) {
	// this.moscow = moscow;
	// }
	// public int getIntField1() {
	// return intField1;
	// }
	// public void setIntField1(int intField1) {
	// this.intField1 = intField1;
	// }
	// public int getIntField2() {
	// return intField2;
	// }
	// public void setIntField2(int intField2) {
	// this.intField2 = intField2;
	// }
	// public int getIntField3() {
	// return intField3;
	// }
	// public void setIntField3(int intField3) {
	// this.intField3 = intField3;
	// }
	// public int getIntField4() {
	// return intField4;
	// }
	// public void setIntField4(int intField4) {
	// this.intField4 = intField4;
	// }
	// public int getIntField5() {
	// return intField5;
	// }
	// public void setIntField5(int intField5) {
	// this.intField5 = intField5;
	// }
	// public String getStrField1() {
	// return strField1;
	// }
	// public void setStrField1(String strField1) {
	// this.strField1 = strField1;
	// }
	// public String getStrField2() {
	// return strField2;
	// }
	// public void setStrField2(String strField2) {
	// this.strField2 = strField2;
	// }
	// public String getStrField3() {
	// return strField3;
	// }
	// public void setStrField3(String strField3) {
	// this.strField3 = strField3;
	// }
	// public String getStrField4() {
	// return strField4;
	// }
	// public void setStrField4(String strField4) {
	// this.strField4 = strField4;
	// }
	// public String getStrField5() {
	// return strField5;
	// }
	// public void setStrField5(String strField5) {
	// this.strField5 = strField5;
	// }
	public Date getArriveDate()
	{
		return arriveDate;
	}

	public void setArriveDate(Date arriveDate)
	{
		this.arriveDate = arriveDate;
	}

	public String getPassportNumber()
	{
		return passportNumber;
	}

	public void setPassportNumber(String passportNumber)
	{
		this.passportNumber = passportNumber;
	}

	public Set<EmployeeLanguage> getEmployeeLanguages()
	{
		return employeeLanguages;
	}

	public void setEmployeeLanguages(Set<EmployeeLanguage> employeeLanguages)
	{
		this.employeeLanguages = employeeLanguages;
	}

	public int getTotalWorkingYear()
	{
		return totalWorkingYear;
	}

	public void setTotalWorkingYear(int totalWorkingYear)
	{
		this.totalWorkingYear = totalWorkingYear;
	}

	// public float getWillFlyTimeOnThisMonth() {
	// return willFlyTimeOnThisMonth;
	// }
	// public void setWillFlyTimeOnThisMonth(float willFlyTimeOnThisMonth) {
	// this.willFlyTimeOnThisMonth = willFlyTimeOnThisMonth;
	// }
	public boolean isTeacher()
	{
		return teacher;
	}

	public void setTeacher(boolean teacher)
	{
		this.teacher = teacher;
	}

	public Set<Stay> getStays()
	{
		return stays;
	}

	public void setStays(Set<Stay> stays)
	{
		this.stays = stays;
	}
}